	var logLevel = 0;
	// Constants for logLevel:
	var LOG_ERROR = 1;
	var LOG_WARNING = 2;
	var LOG_INFO = 3;
	var LOG_MOREINFO = 4;
	
	var lastMemeListRequest;
	
	localStorage.requestTimeout = localStorage.requestTimeout || (1000 * 5);


	// Retrieve from Meemi the meme list selected
	function retrieveMemeListJSON(page){
		lastMemeListRequest=page;
		//gets the complete url to make the request to Meemi
		page = getMeemiAPIURL(page);
		//preparing the parameters to make the request to Meemi
		parameters={meemi_id:localStorage.username,
				pwd:localStorage.password,
				app_key:applicationKey};

		var abortTimerId = window.setTimeout( function() {
			writeLog( "Timeout retrieveReplies after " + localStorage.requestTimeout + " seconds.", LOG_WARNING );
			$('#meemi-memelist').find(".temp").append("<br/>attendi ancora...");
		}, localStorage.requestTimeout );

		//makes the request to Meemi
		$.ajax({
			url: page,
			type: 'POST',
			data: parameters,
			dataType: 'json',
			// the following function will be executed only if the message from Meemi is a perfect JSON
			success: function(data){
				writeLog('messaggio ricevuto',LOG_INFO);
				$('#meemi-memelist').find(".temp").append("<br/>retrieved..."); //show the message to the user
				window.clearTimeout( abortTimerId );
				
				//Meemi can return also an error, in this case the error will be displayed
				if(!data){
					writeLog('nessun contenuto restituito',LOG_ERROR);
					$('#meemi-memelist').find(".temp").append("<br/>errore: Meemi non vuole rispondere");
				}
				if(data.error){
					writeLog(data.error.code,LOG_ERROR);
					$('#meemi-memelist').find(".temp").append("<br/>errore: "+data.error.message);
				}else{
				//in the case the message from Meemi isn't an error
				//this is the loop for every meme returned by Meemi
					//what was the call?
					dataContentType = url.match(/only_new_followers/)?'user':'meme';
					$.each(data,function(i,meme) {
						switch(dataContentType){
							case 'meme':
								//the meme is already there? if not then will be appended in the DIV#meemi-memelist
								if($('#meme'+meme.id).length==0){
									$('#meemi-memelist').append('<div id="meme'+meme.id+'" class="meme"></div>');
									newMeme=$('#meme'+meme.id).hide(); //the meme will be shown only at the end of making this
									//show the avatar of the author
									newMeme.append('<div class="avatar">'
												  +'<a href="javascript:openPage(\'http://meemi.com/'+meme.screen_name+'/'+meme.id+'\')" >'
												  +'<img src="'+meme.avatar+'" width="32" height="32" /> '
												  +'</a>'
												  +'</div>');
									//show the name of the author
									newMeme.append('<div class="screen_name"> '
												  +'<a href="javascript:openPage(\'http://meemi.com/'+meme.screen_name+'\')" >'
												  +meme.screen_name
												  +'</a> '
												  +'</div> ');
									//show the action icons, only which is needed
									newMeme.append('<div class="icone">'
												  +'<a href="javascript:favourite(\''+meme.screen_name+'\',\''+meme.id+'\')"><img id="favourite_'+meme.id+'" src="icons/fav_'+(meme.is_preferite?1:0)+'.png" /></a>'
												  +'<a href="javascript:mark_read(\''+meme.id+'\')"><img id="mark_'+meme.id+'" src="icons/mark.png" /></a>'
												  +'</div>');
									newMeme.append('<div class="brk"></div> ');
									//based on the content type create the body of the meme, then fill it
									newMeme.append('<div class="body_meme"></div>');
									memeBody=newMeme.find('.body_meme');
										//fill the contents of the meme based on its type
										switch(meme.meme_type){
											case 'video':
												videoImage = 'embedded_content.jpg';
												//if the video is from YouTube, show the thumbnail
												if(ytid=meme.video.match(YOUTUBE_REGEXP))
													videoImage = 'http://img.youtube.com/vi/'+ytid[1]+'/default.jpg';
												//cliking on the image will bring the user on the meme page
												memeBody.append('<a href="javascript:openPage(\'http://meemi.com/'+meme.screen_name+'/'+meme.id+'\')" style="background-image:url('+videoImage+')" class="vis_video">'
															   +'<img src="play_button.png">'
															   +'</a><br />'
															   +meme.content);
												break;
											case 'event':
												memeBody.append('<a href="javascript:openPage(\'http://meemi.com/'+meme.screen_name+'/'+meme.id+'\')">evento</a>');
												break;
											case 'link':
												memeBody.append('<a class="bb" href="'+meme.link+'" rel="nofollow">'
															   +meme.content+'</a>');
												break;
											case 'image':
												//cliking on the image will bring the user on the meme page
												memeBody.append('<a href="javascript:openPage(\'http://meemi.com/'+meme.screen_name+'/'+meme.id+'\')">'
																+'<img class="img" src="'+meme.image_small+'">'
															   +'</a><br />'
															   +meme.content);
												break;
											case 'quote':
												memeBody.append('<img src="http://meemi.com/stc/i/v2.sx.png"> '
															   +'<div class="q">'+meme.content+'</div> '
															   +'<br /><img src="http://meemi.com/stc/i/v2.dx.png">'
															   +'<div class="s">- '+meme.source+'</div>');
												break;
											case 'text':
											default:
												memeBody.append(meme.content);
										}
										
										//create a DIV for the options then fill it
										memeBody.append('<div class="opt"></div>');
										memeOpt=memeBody.find('.opt');
											//memeOpt.append('1 giorno, '); //time of the meme submission
											//memeOpt.append('<i><a href=\'http://meemi.com/m/p/search/@l:Milano\'>Milano</a></i>  - '); //location of the user
											memeOpt.append('<b><small>');
											//replies
											if(meme.qta_replies==0){
												memeOpt.append('nessuna risposta');
											}else{
												memeOpt.append('<a class="viewReplies" href="javascript:void(0);" onclick="retrieveReplies(\''+meme.screen_name+'\','+meme.id+','+(meme.qta_replies)+')">'+meme.qta_replies+' rispost'+(meme.qta_replies==1?'a':'e')+'</a>');
											}
											memeOpt.append('</small></b>');
											//this makes the div for the replies, empty by default, will be filled by clicking on the previous link
											memeOpt.append('<div class="replies"></div>');
								}
								break; //case 'meme'
							case 'user':
								//the meme is already there? if not then will be appended in the DIV#meemi-memelist
								if($('#user_'+meme.screen_name).length==0){
									$('#meemi-memelist').append('<div id="user_'+meme.screen_name+'" class="meme"></div>');
									newUser=$('#user_'+meme.screen_name).hide(); //the meme will be shown only at the end of making this
									//show the avatar of the author
									newUser.append('<div class="avatar">'
												  +'<a href="javascript:openPage(\'http://meemi.com/'+meme.screen_name+'/'+meme.id+'\')" >'
												  +'<img src="'+meme.avatar+'" width="32" height="32" /> '
												  +'</a>'
												  +'</div>');
									//show the name of the user
									newUser.append('<div class="screen_name"> '
												  +'<a href="javascript:openPage(\'http://meemi.com/'+meme.screen_name+'\')" >'
												  +meme.screen_name
												  +'</a> '
												  +'</div> ');
									//show the action icons, only which is needed
									newUser.append('<div class="icone">'
												  //tbd: actions for users (not supported by Meemi)
												  +'</div>');
									newUser.append('<div class="brk"></div> ');
									newUser.append('<div class="body_user"></div>');
									userBody=newUser.find('.body_user');
										userBody.append(meme.description||'(nessuna descrizione)');
										//create a DIV for the options then fill it
										userBody.append('<div class="opt"></div>');
										userOpt=userBody.find('.opt');
											userOpt.append('<b><small>');
											//following?
											if(meme.you_follow)
												userOpt.append('stai seguendo questo utente'
															   +'<a href="javascript:follow(\''+meme.screen_name+'\',\'unfollow\');" >'
															   +'non seguirlo pi&ugrave;'
															   +'</a>');
											else
												userOpt.append('non stai seguendo questo utente, '
															   +'<a href="javascript:follow(\''+meme.screen_name+'\',\'follow\');" >'
															   +'segui l\'utente'
															   +'</a>');
											userOpt.append('</small></b>');
											//tbd: last memes
											//memeOpt.append('<div class="replies"></div>');
								}
								break;
						}
					});
					//at the end of loop for every meme, show the memes retreived
					$('#meemi-memelist').slideUp('slow',function(){
						$('#meemi-memelist').find('.temp').hide();
						$('#meemi-memelist').find('.meme').show();
						$('#meemi-memelist').slideDown('slow');
					});
				}
			},
			//this function will be executed only if the data from Meemi is not valid
			error:function (xhr, ajaxOptions, thrownError){
				window.clearTimeout( abortTimerId );
				writeLog(xhr.status,LOG_ERROR);
				writeLog(thrownError,LOG_ERROR);
				//show the snipplet of the error
				$('#meemi-memelist').find(".temp").append("<br/>errore durante la lettura dei memi: <code>"+thrownError.toString().substring(0,42)+"...</code>")
				//show the complete error
				localStorage.lastError = thrownError.toString();
				writeLog(localStorage.lastError,LOG_ERROR);
				if(ajaxOptions=='parsererror'){
					localStorage.lastError = xhr.responseText;
					writeLog(localStorage.lastError,LOG_MOREINFO);
					$('#meemi-memelist').find(".temp").append("<a href='#' onclick=\"javascript:$('#meemi-memelist').find('.temp').append('</br><textarea>'+localStorage.lastError+'</textarea>');\"><img src='icons/information.png'></a>");
				}
			}    
		});
	}	
	
	function retrieveReplies(user,meme_id,num){
		num = num || 5; //number of messages is 5 by default
		//page example: "http://meemi.com/api3/screen_name/id_meme/replies/start/qta"
		page=getMeemiAPIURL(null,user,"/"+meme_id+"/replies/-/"+num);
			parameters={meemi_id:localStorage.username,
				    pwd:localStorage.password,
					app_key:applicationKey};
		

		$("#meme"+meme_id).find('.opt').append('<span class="temp">retreiving...</span>');

		var abortTimerId = window.setTimeout( function() {
			writeLog( "Timeout retrieveReplies after " + localStorage.requestTimeout + " seconds.", LOG_WARNING );
			$("#meme"+meme_id).find('.temp').append("<br/>attendi ancora...");
		}, localStorage.requestTimeout );

		//make the request
		$.ajax({
			url: page,
			type: 'POST',
			data: parameters,
			dataType: 'json',
			success: function(data){
				writeLog('messaggio ricevuto',LOG_INFO);
				window.clearTimeout( abortTimerId );
				$("#meme"+meme_id).find('.temp').append("<br/>retrieved...");
				if(data.error){
					writeLog(data.error.code,LOG_ERROR);
					$("#meme"+meme_id).find('.temp').append("<br/>errore: "+data.error.message);
				}else{
					$.each(data,function(i,meme) {
						replies=$("#meme"+meme_id).find(".replies");
						replies.append('<div id="meme'+meme.id+'" class="reply '+(meme.screen_name==localStorage.username?'mine':'')+'"></div>');
						reply=$('#meme'+meme.id);
						reply.append('<span class="r_screen_name">'+meme.screen_name+'</span> ');
						switch(meme.meme_type){
							case 'video':
							case 'event':
								reply.append(meme.meme_type+': <a href="javascript:openPage(\'http://meemi.com/'+meme.screen_name+'/'+meme.id+'\')">'+(meme.content?meme.content:'visualizza')+'</a>');
								break;
							case 'link':
								reply.append('<a class="bb" href="'+meme.link+'">'
											   +meme.content+'</a>');
								break;
							case 'image':
								//cliking on the image will bring the user on the meme page
								reply.append('<a href="javascript:openPage(\'http://meemi.com/'+meme.screen_name+'/'+meme.id+'\')">'
												+'<img class="img" src="'+meme.image_small+'">'
											   +'</a><br />'
											   +meme.content);
								break;
							case 'quote':
								reply.append('<span class="quote">'+meme.content+'</span> '
											   +'<span class="quote_author">('+meme.source+')</span>');
								break;
							case 'text':
							default:
								reply.append(meme.content);
						}
					});
					$("#meme"+meme_id).find('.temp').hide();
					$("#meme"+meme_id).find('a.viewReplies').hide();
				}
			},
			error:function (xhr, ajaxOptions, thrownError){
				writeLog(xhr.status,LOG_ERROR);
				writeLog(thrownError,LOG_ERROR);
				localStorage.lastError = thrownError;
				$("#meme"+meme_id).find('.temp').append("<br/>errore durante la lettura dei memi: <code>"+thrownError.substring(0,42)+"...</code>")
				$("#meme"+meme_id).find('.temp').append("<a href='#' onclick=\"javascript:$('#meme'+meme_id).find('.temp').append('</br><textarea>'+localStorage.lastError+'</textarea>');\"><img src='icons/information.png'></a>");
			}    
		});
	}	
	
	function mark_read(meme_id){
		page=getMeemiAPIURL('mark',localStorage.username,"/"+meme_id);
		//page="http://meemi.com/api3/"+user+"/"+meme_id+"/replies/-/5/html-json";
			parameters={meemi_id:localStorage.username,
				    pwd:localStorage.password,
					app_key:applicationKey};

		$("#mark_"+meme_id).attr("src","icons/loading.gif");

		$.ajax({
			url: page,
			type: 'POST',
			data: parameters,
			dataType: 'json',
			success: function(data){
				writeLog('messaggio ricevuto',LOG_INFO);
				if(data.message.status==1){
					$('#meme'+meme_id).slideUp('slow');
				}else{
					writeLog('non riesco a segnare come letto il meme '+meme_id,LOG_ERROR);
					$("#mark_"+meme_id).attr("src","icons/error.png");
				}
				if(notificationToDecrease=lastMemeListRequest.match(/^only_new_(.*)/)[1]){
					var notificationCount = JSON.parse(localStorage.notificationCount);
					notificationCount[notificationToDecrease]--;
					localStorage.notificationCount = JSON.stringify(notificationCount);
					createSelector();
					
						//recount for the badge
						var notification = JSON.parse(localStorage.notification);
						var badgeValue = 0;
						$.each(notificationCount,function(key,val) {
							if(notification[key]){
								badgeValue += val;
							}
						});
						str = badgeValue==0 ? '' : badgeValue.toString();
						chrome.browserAction.setBadgeText( {text: badgeValue.toString()} );
				}
			},
			error:function (xhr, ajaxOptions, thrownError){
				writeLog('non riesco a segnare come letto il meme, seguono dettagli',LOG_ERROR);
				writeLog(xhr.status,LOG_ERROR);
				writeLog(thrownError,LOG_ERROR);
				$("#mark_"+meme_id).attr("src","icons/error.png");
			}    
		});

	}

	function favourite(user,meme_id){
		page=getMeemiAPIURL('fav',null,"/"+user+"/"+meme_id);
		//http://meemi.com/api3/p/fav/screen_name/id_meme
			parameters={meemi_id:localStorage.username,
				    pwd:localStorage.password,
					app_key:applicationKey};

		$("#favourite_"+meme_id).attr("src","icons/loading.gif");

		$.ajax({
			url: page,
			type: 'POST',
			data: parameters,
			dataType: 'json',
			success: function(data){
				writeLog('messaggio ricevuto',LOG_INFO);
					if(data.message.status==1){
						//$('#meme'+meme_id).slideUp('slow');
						$("#favourite_"+meme_id).attr("src","icons/fav_1.png");
					}else{
						writeLog('non riesco a segnare meme '+meme_id+' come preferito',LOG_ERROR);
						$("#favourite_"+meme_id).attr("src","icons/error.png");
					}
			},
			error:function (xhr, ajaxOptions, thrownError){
				writeLog('non riesco a segnare meme '+meme_id+' come preferito',LOG_ERROR);
				writeLog(xhr.status,LOG_ERROR);
				writeLog(thrownError,LOG_ERROR);
				$("#favourite_"+meme_id).attr("src","icons/error.png");
			}    
		});
	}
	
	function follow(user,wish){
		sourceLink = $('#user_LorenzoMele').find('.opt').find('a');
		page=getMeemiAPIURL(wish,null,"/"+user);
		//http://meemi.com/api3/p/follow/screen_name
		//http://meemi.com/api3/p/unfollow/screen_name
			parameters={meemi_id:localStorage.username,
				    pwd:localStorage.password,
					app_key:applicationKey};

		sourceLink.html("...");

		$.ajax({
			url: page,
			type: 'POST',
			data: parameters,
			dataType: 'json',
			success: function(data){
				writeLog('messaggio ricevuto',LOG_INFO);
				if(data.error){
					writeLog(data.error.code,LOG_ERROR);
					sourceLink.html("errore");
				}else{
					if(data.message.status==1){
						mesg=$(sourceLink[0].parentElement);
						if(wish=='follow'){
							sourceLink.html("non seguire pi&ugrave;");
							sourceLink.attr("href",sourceLink.attr("href").replace(/'follow'/i,"'unfollow'"));
							mesg.html(mesg.html().replace(/non stai seguendo/i,"stai seguendo"));
						}else{
							sourceLink.html("segui l'utente");
							sourceLink.attr("href",sourceLink.attr("href").replace(/'unfollow'/i,"'follow'"));
							mesg.html(mesg.html().replace(/stai seguendo/i,"non stai seguendo"));
						}
					}else{
						writeLog('non riesco a fare il '+wish+' dell\'utente '+user,LOG_ERROR);
						sourceLink.html("errore");
					}
				}
			},
			error:function (xhr, ajaxOptions, thrownError){
				writeLog('non riesco a fare il '+wish+' dell\'utente '+user,LOG_ERROR);
				writeLog(xhr.status,LOG_ERROR);
				writeLog(thrownError,LOG_ERROR);
				sourceLink.html("errore");
			}    
		});
	}
